package mornd.test3;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * spring 推荐方式实现监听器适配调用
 */

@Component("applicationEventMulticaster") // beanName 是固定的，用于覆盖掉 spring 默认的事件发布器
class MyEventMulticaster1 extends AbstractEventMulticaster {

    @Autowired
    private ThreadPoolTaskExecutor executor;

    /**
     * 保存所有自己添加的监听器
     * 泛型为包装后，可判断事件类型的监听器
     */
    private final List<GenericApplicationListener> listeners = new ArrayList<>();

    /**
     * 收集监听器
     * @param listener 监听器对象
     */
    @Override
    public void addApplicationListener(ApplicationListener listener) {
        // 获取监听器实现的接口
        ResolvableType[] interfaces = ResolvableType.forClass(listener.getClass()).getInterfaces();
        for (ResolvableType anInterface : interfaces) {
            // 这里直接获取接口的第一个泛型，也就是事件类型
            ResolvableType generic = anInterface.getGeneric(0);

            // 原始的监听器无法判断事件类型，需要封装成它的子类型
            GenericApplicationListener genericApplicationListener = new GenericApplicationListener() {
                @Override // 调用原始监听器的方法
                public void onApplicationEvent(ApplicationEvent event) {
                    // 异步执行
                    executor.submit(()-> listener.onApplicationEvent(event));
                }

                @Override // 是否支持某事件类型，参数是真实的事件类型
                public boolean supportsEventType(ResolvableType eventType) {
                    return generic.isAssignableFrom(eventType);
                }
            };

            listeners.add(genericApplicationListener);
        }
    }

    /**
     * 收集监听器
     * @param listenerBeanName 实现监听器接口的 beanName
     */
    @Override
    public void addApplicationListenerBean(String listenerBeanName) {
    }

    /**
     * 真正发事件方法
     */
    /**
     *
     * @param event 这里 spring 也会传入其它的事件 比如：ContextRefreshedEvent，所以需要做校验，否则类型转换错误
     * @param eventType
     */
    @Override
    public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
        for (GenericApplicationListener listener : listeners) {
            if(listener.supportsEventType(ResolvableType.forClass(event.getClass()))) {
                listener.onApplicationEvent(event);
            }
        }
    }
}
